package cn.edu.sgu.www.mhxysy.service.gang.impl;

import cn.edu.sgu.www.mhxysy.pager.Pager;
import cn.edu.sgu.www.mhxysy.consts.MimeTypes;
import cn.edu.sgu.www.mhxysy.dto.gang.GangMemberDTO;
import cn.edu.sgu.www.mhxysy.easyexel.impl.GangMemberExcelData;
import cn.edu.sgu.www.mhxysy.entity.gang.Gang;
import cn.edu.sgu.www.mhxysy.entity.gang.GangJob;
import cn.edu.sgu.www.mhxysy.entity.gang.GangMember;
import cn.edu.sgu.www.mhxysy.entity.role.RoleCategory;
import cn.edu.sgu.www.mhxysy.entity.school.School;
import cn.edu.sgu.www.mhxysy.mapper.gang.GangMemberMapper;
import cn.edu.sgu.www.mhxysy.service.gang.GangJobService;
import cn.edu.sgu.www.mhxysy.service.gang.GangMemberService;
import cn.edu.sgu.www.mhxysy.service.gang.GangService;
import cn.edu.sgu.www.mhxysy.service.role.RoleCategoryService;
import cn.edu.sgu.www.mhxysy.service.school.SchoolService;
import cn.edu.sgu.www.mhxysy.util.HttpUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class GangMemberServiceImpl implements GangMemberService {

	private final GangService gangService;
	private final SchoolService schoolService;
	private final GangJobService gangJobService;
	private final GangMemberMapper gangMemberMapper;
	private final RoleCategoryService roleCategoryService;

	@Autowired
	public GangMemberServiceImpl(
			GangService gangService,
			SchoolService schoolService,
			GangJobService gangJobService,
			GangMemberMapper gangMemberMapper,
			RoleCategoryService roleCategoryService) {
		this.gangService = gangService;
		this.schoolService = schoolService;
		this.gangJobService = gangJobService;
		this.gangMemberMapper = gangMemberMapper;
		this.roleCategoryService = roleCategoryService;
	}

	@Override
	public void exportData() throws UnsupportedEncodingException {
		String fileName = StringUtils.encode("帮派成员列表.xlsx");
		HttpServletResponse response = HttpUtils.getResponse();

		response.setCharacterEncoding("utf-8");
		response.setHeader("Content-disposition", "attachment;filename=" + fileName);
		response.setContentType(MimeTypes.APPLICATION_SHEET);

		try (ServletOutputStream outputStream = response.getOutputStream()) {
			List<GangMember> gangMembers = gangMemberMapper.selectList(null);

			List<GangMemberExcelData> excelData = gangMembers.stream().map(new Function<GangMember, GangMemberExcelData>() {
				@Override
				public GangMemberExcelData apply(GangMember gangMember) {
					return toExcelData(gangMember);
				}
			}).collect(Collectors.toList());

			// 帮派
			List<Gang> gangs = gangService.selectAll();
			// 帮派职务
			List<GangJob> jobs = gangJobService.selectAll();
			// 门派
			List<School> schools = schoolService.selectAll();
			// 角色造型
			List<RoleCategory> modelings = roleCategoryService.selectAll();

			// 要导出的总记录数
			int size = gangMembers.size();

			// 给指定列添加下拉框
			SheetWriteHandler writeHandler = new SheetWriteHandler() {
				@Override
				public void afterSheetCreate(SheetWriteHandlerContext context) {
					Sheet sheet = context.getWriteSheetHolder().getSheet();
					DataValidationHelper helper = sheet.getDataValidationHelper();

					// 角色造型：cols4
					sheet.addValidationData(helper.createValidation(helper.createExplicitListConstraint(modelings.stream().map(new Function<RoleCategory, String>() {
						@Override
						public String apply(RoleCategory roleModeling) {
							return roleModeling.getName();
						}
					}).toArray(String[]::new)), new CellRangeAddressList(1, size, 3, 3)));

					// 门派：cols5
					sheet.addValidationData(helper.createValidation(helper.createExplicitListConstraint(schools.stream().map(new Function<School, String>() {
						@Override
						public String apply(School school) {
							return school.getName();
						}
					}).toArray(String[]::new)), new CellRangeAddressList(1, size, 4, 4)));

					// 帮派职务：cols6
					sheet.addValidationData(helper.createValidation(helper.createExplicitListConstraint(jobs.stream().map(new Function<GangJob, String>() {
						@Override
						public String apply(GangJob job) {
							return job.getName();
						}
					}).toArray(String[]::new)), new CellRangeAddressList(1, size, 5, 5)));

					// 帮派：cols7
					sheet.addValidationData(helper.createValidation(helper.createExplicitListConstraint(gangs.stream().map(new Function<Gang, String>() {
						@Override
						public String apply(Gang gang) {
							return gang.getName();
						}
					}).toArray(String[]::new)), new CellRangeAddressList(1, size, 6, 6)));
				}
			};

			EasyExcel.write(outputStream, GangMemberExcelData.class).sheet("帮派成员列表")
					.registerWriteHandler(writeHandler)
					.doWrite(excelData);
		} catch (Exception e) {
			e.printStackTrace();

			HttpUtils.exportFail(response);
		}
	}

	@Override
	public void importData(MultipartFile file) throws IOException {
		// 帮派
		List<Gang> gangs = gangService.selectAll();
		// 帮派职务
		List<GangJob> jobs = gangJobService.selectAll();
		// 门派
		List<School> schools = schoolService.selectAll();
		// 角色造型
		List<RoleCategory> modelings = roleCategoryService.selectAll();

		// 查询所有帮派成员信息
		List<GangMember> list = gangMemberMapper.selectList(null);

		// 把帮派成员信息以ID为key保存到map中
		Map<String, GangMember> map = transferToMap(list);

		// 读excel表
		List<GangMember> members = new ArrayList<>();

		EasyExcel.read(file.getInputStream(), GangMemberExcelData.class, new ReadListener<GangMemberExcelData>() {
			@Override
			public void invoke(GangMemberExcelData data, AnalysisContext context) {
				GangMember gangMember = new GangMember();

				gangMember.setId(data.getId());
				gangMember.setName(data.getName());
				gangMember.setGrade(data.getGrade());
				gangMember.setLsbg(data.getLsbg());
				gangMember.setBzbg(data.getBzbg());
				gangMember.setXybg(data.getXybg());
				gangMember.setEnterTime(data.getEnterTime());
				gangMember.setLastOnline(data.getLastOnline());

				// 设置外键
				for (RoleCategory modeling : modelings) {
					if (modeling.getName().equals(data.getRole())) {
						gangMember.setRoleId(modeling.getId());

						break;
					}
				}
				for (GangJob job : jobs) {
					if (job.getName().equals(data.getJob())) {
						gangMember.setJobId(job.getId());

						break;
					}
				}
				for (Gang gang : gangs) {
					if (gang.getName().equals(data.getGang())) {
						gangMember.setGangId(gang.getId());

						break;
					}
				}
				for (School school : schools) {
					if (school.getName().equals(data.getSchool())) {
						gangMember.setSchoolId(school.getId());

						break;
					}
				}

				if (map.containsKey(data.getId())) {
					gangMemberMapper.updateById(gangMember);
				} else {
					// 保存到list
					members.add(gangMember);
				}
			}

			@Override
			public void doAfterAllAnalysed(AnalysisContext context) {

			}
		}).sheet().doRead();

		// 批量插入
		gangMemberMapper.insertList(members);
	}

	@Override
	public void insert(GangMemberDTO memberDTO) {
		GangMember gangMember = toEntity(memberDTO);

		gangMemberMapper.insert(gangMember);
	}

	@Override
	public void deleteById(String id) {
		gangMemberMapper.deleteById(id);
	}

	@Override
	public void updateById(GangMemberDTO memberDTO) {
		GangMember gangMember = toEntity(memberDTO);

		gangMemberMapper.updateById(gangMember);
	}

	@Override
	public Page<GangMember> selectByPage(Pager<GangMember> pager) {
		QueryWrapper<GangMember> queryWrapper = Pager.getQueryWrapper(pager, true);
		Page<GangMember> page = Pager.ofPage(pager);

		return gangMemberMapper.selectPage(page, queryWrapper);
	}

	private GangMember toEntity(GangMemberDTO memberDTO) {
		GangMember gangMember = new GangMember();

		gangMember.setId(memberDTO.getId());
		gangMember.setName(memberDTO.getName());
		gangMember.setBzbg(memberDTO.getBzbg());
		gangMember.setXybg(memberDTO.getXybg());
		gangMember.setLsbg(memberDTO.getLsbg());
		gangMember.setGrade(memberDTO.getGrade());
		gangMember.setJobId(memberDTO.getJobId());
		gangMember.setRoleId(memberDTO.getRoleId());
		gangMember.setGangId(memberDTO.getGangId());
		gangMember.setSchoolId(memberDTO.getSchoolId());
		gangMember.setEnterTime(memberDTO.getEnterTime());
		gangMember.setLastOnline(memberDTO.getLastOnline());

		return gangMember;
	}

	/**
	 * 数据库实体类转化为excel实体类
	 * @param gangMember GangMember
	 * @return GangMemberExcelData
	 */
	private GangMemberExcelData toExcelData(GangMember gangMember) {
		GangMemberExcelData excelData = new GangMemberExcelData();

		excelData.setId(gangMember.getId());
		excelData.setName(gangMember.getName());
		excelData.setGrade(gangMember.getGrade());
		excelData.setBzbg(gangMember.getBzbg());
		excelData.setLsbg(gangMember.getLsbg());
		excelData.setXybg(gangMember.getXybg());
		excelData.setEnterTime(gangMember.getEnterTime());
		excelData.setLastOnline(gangMember.getLastOnline());

		Gang gang = gangService.selectById(gangMember.getGangId());
		GangJob gangJob = gangJobService.selectById(gangMember.getJobId());
		School school = schoolService.selectById(gangMember.getSchoolId());
		RoleCategory roleCategory = roleCategoryService.selectById(gangMember.getRoleId());

		// 设置需要转换的字段
		excelData.setGang(gang.getName());
		excelData.setJob(gangJob.getName());
		excelData.setSchool(school.getName());
		excelData.setRole(roleCategory.getName());

		return excelData;
	}

	/**
	 * list转为map
	 * @param list List<GangMember>
	 * @return Map<String, GangMember>
	 */
	private Map<String, GangMember> transferToMap(List<GangMember> list) {
		// 把帮派成员信息以ID为key保存到map中
		Map<String, GangMember> hashMap = new HashMap<>(list.size());

		list.forEach(new Consumer<GangMember>() {
			@Override
			public void accept(GangMember gangMember) {
				hashMap.put(gangMember.getId(), gangMember);
			}
		});

		return hashMap;
	}

}